<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
<html>
<head>
<!--

  @(#)package.html	

Copyright (C) 2010  Belledonne Communications, Grenoble, France

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.


-->
</head>
<body bgcolor="white">

Liblinphone is a high level library for bringing SIP video call functionnality into an application. It aims at making easy the integration of the SIP video calls into any applications. All variants of linphone are directly based on it:

	<li>linphone (GUI interface)
	<li>linphonec (console interface)
<br> Liblinphone is GPL (see COPYING file). Please understand the licencing details before using it!

<br>For any use of this library beyond the rights granted to you by the GPL license, please contact Belledonne Communications (contact@belledonne-communications.com)




<h2>Package Specification</h2>

LibLinphone package is organized in submodules.
<ul>
  <li><a href="#proxy">Managing proxies</a></li>
</ul>
<ul>
  <li><a href="#buddy">Managing Buddies and buddy list and presence</a></li>
</ul>
<ul>
  <li><a href="#chat">Chat room and Messaging</a></li>
</ul>
<ul>
  <li><a href="#echo">Sound and echo cancellation settings</a></li>
</ul>


<h2>Related Documentation</h2>

For overviews, tutorials, examples, guides, and tool documentation, please see:
<ul>
  <li><a href="http://www.linphone.org">linphone web site</a>
</ul>

<!-- Put @see and @since tags down here. -->
<h3>
<a name="proxy">Managing proxies</a>
</h3>
User registration is controled by  {@link org.linphone.core.LinphoneProxyConfig } settings.
<br> Each {@link org.linphone.core.LinphoneProxyConfig } object can be configured with registration informations 
like {@link org.linphone.core.LinphoneProxyConfig#setProxy proxy address } , {@link org.linphone.core.LinphoneProxyConfig#setIdentity user id}, and so on. 
<br> A created proxy config using {@link org.linphone.core.LinphoneCoreFactory#createProxyConfig }, once configured, must be added to {@link org.linphone.core.LinphoneCore} using function {@link org.linphone.core.LinphoneCore#addProxyConfig }.
<br> It is recommended to set a default {@link org.linphone.core.LinphoneProxyConfig proxy config }  using function {@link org.linphone.core.LinphoneCore#setDefaultProxyConfig }. Once done, if {@link org.linphone.core.LinphoneProxyConfig a proxy config } has been configured with attribute {@link org.linphone.core.LinphoneProxyConfig#enableRegister enable register }  , next call to {@link org.linphone.core.LinphoneCore#iterate } triggers a SIP register.  
<br> Registration status is reported by {@link org.linphone.core.LinphoneCoreListener#registrationState registration listener}.
<br>
<br> This pseudo code demonstrates basic registration operations:
<br> 
<pre>
<code>
	
	LinphoneProxyConfig proxy_cfg;
	/*create proxy config*/
	proxy_cfg = LinphoneCoreFactory.instance().createProxyConfig();
	/*parse identity*/
	LinphoneAddress from = LinphoneCoreFactory.instance().createAddress("sip:toto@sip.titi.com");
	LinphoneAuthInfo info;
	if (password!=NULL){
 		info=LinphoneCoreFactory.instance().createAuthInfo(from.getUsername(),null,"secret",null,null); /*create authentication structure from identity*/
		lc.addAuthInfo(info); /*add authentication info to LinphoneCore*/
	}	
	// configure proxy entries
	proxy_cfg.setIdenty(identity); /*set identity with user name and domain*/
	String server_addr = from.getDomain(); /*extract domain address from identity*/
	proxy_cfg.setProxy(server_addr); /* we assume domain = proxy server address*/
	proxy_cfg.enableRegister(true); /*activate registration for this proxy config*/
	
	lc.addProxyConfig(proxy_cfg); /*add proxy config to linphone core*/
	lc.setDefaultProxyconfig(proxy_cfg); /*set to default proxy*/ 
</code>
</pre>
<br>
  {@link org.linphone.core.LinphoneCoreListener#registrationState Registration state listener} :
<pre>
<code>
 void registrationState(LinphoneCore lc, LinphoneProxyConfig cfg, LinphoneCore.RegistrationState cstate, String message){
		System.out.println(New registration state ["+cstate+"] for user id ["+cfg.getUserName()+"] at proxy ["+cfg.getProxy()+"]";
}
</pre>
</code>

<br><b>Authentication:</b>
<br>Most of the time, registration requires {@link org.linphone.core.LinphoneAuthInfo authentication } to succed. {@link org.linphone.core.LinphoneAuthInfo} info must be either added to {@link org.linphone.core.LinphoneCore } using method {@link org.linphone.core.LinphoneCore#addAuthInfo } before {@link org.linphone.core.LinphoneProxyConfig} is added to Linphone core, or on demand from listener {@link org.linphone.core.LinphoneCoreListener#authInfoRequested(LinphoneCore, String, String)}  .    
<br>
<br><b>Unregistration:</b>
<br> Unregistration or any changes to {@link org.linphone.core.LinphoneProxyConfig} must be first started by a call to function {@link org.linphone.core.LinphoneProxyConfig#edit } and validated by  function {@link org.linphone.core.LinphoneProxyConfig#done }
<br> This pseudo code shows how to unregister a user associated to a{@link org.linphone.core.LinphoneProxyConfig}
<pre>
<code>
 	LinphoneProxyConfig proxy_cfg;
 	lc.setDefaultProxyConfig(proxy_cfg); /* get default proxy config*/
	proxy_cfg.edit(); /*start editing proxy configuration*/
	proxy_cfg.enableRegister(false); /*de-activate registration for this proxy config*/
	proxy_cfg.done(); /*initiate REGISTER with expire = 0*/
</pre>
</code>
<br>
<br>
<h3>
<a name="buddy">Managing Buddies and buddy list and presence</a>
</h3>
<br>
<b>Buddies and buddy list</b>
<br>Each buddy is represented by a {@link org.linphone.core.LinphoneFriend } object created by function {@link org.linphone.core.LinphoneCoreFactory#createLinphoneFriend()}. 
Buddy configuration parameters like {@link org.linphone.core.LinphoneFriend#setAddress(LinphoneAddress) sip uri} or  {@link org.linphone.core.LinphoneFriend#setIncSubscribePolicy(LinphoneFriend.SubscribePolicy) status publication}  are configurable for each buddy.
<br>Here under a typical buddy creation:
<br>
<pre>
<code>
	LinphoneFriend my_friend=LinphoneFactory.instance().createFriend("sip:joe@sip.linphone.org"); /*creates friend object for buddy joe*/
	my_friend.enableSubscribes(true); /*configure this friend to emit SUBSCRIBE message after being added to LinphoneCore*/
	my_friend.setIncSubscribePolicy(LinphoneFriend.SubscribePolicy.Accept); /* accept Incoming subscription request for this friend*/
</code>
</pre>
{@link LinphoneFriend  friends } status changes are reported by  {@link org.linphone.core.LinphoneCoreListener#notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf)} .
<pre>
<code>
 void notifyPresenceReceived(LinphoneCore lc, LinphoneFriend lf){
	LinphoneAddress friend_address = lf.getAddress();
	System.out.println("New state ["+lf.getStatus()+"] for user id ["+friend_address+"] ");
}
</code>
</pre>

<br>Once created a buddy can be added to the buddy list using function {@link org.linphone.core.LinphoneCore#addFriend(LinphoneFriend lf) } . Added friends will be notified about {@link org.linphone.core.LinphoneCore#setPresenceInfo(int minute_away,String alternative_contact, OnlineStatus status) local status changes }
<br>
Any subsequente modifications to {@link org.linphone.core.LinphoneFriend} must be first started by a call to function  to {@link org.linphone.core.LinphoneFriend#edit()} and validated by  function {@link org.linphone.core.LinphoneFriend#done()}
<pre>
<code>
	my_friend.edit(); /* start editing friend */
	my_friend.enableSubscribes(true); /*disable subscription for this friend*/
	my_friend.done(); /*commit changes triggering an UNSUBSCRIBE message*/
</code>
</pre>

<b> Publishing presence status </b>
<br>Local presence status can be changed using function {@link org.linphone.core.LinphoneCore#setPresenceInfo }.New status is propagated to all friends {@link org.linphone.core.LinphoneCore#addFriend(LinphoneFriend lf)  previously added } to LinphoneCore. 
<br>
<br>
<b>Handling incoming subscription request</b>
<br> New incoming subscription requests are process according to{@link org.linphone.core.LinphoneFriend#setIncSubscribePolicy(LinphoneFriend.SubscribePolicy)  the incoming subscription policy state}  for subscription initiated by {@link org.linphone.core.LinphoneCore#addFriend(LinphoneFriend lf) members of the buddy list. }
<br> For incoming request coming from an unknown buddy, the call back  {@link org.linphone.core.LinphoneCoreListener#newSubscriptionRequest(LinphoneCore lc, LinphoneFriend lf, String url)}

<h3>
<a name="chat">Chat room and Messaging</a>
</h3>
<b> Exchanging text messages</b>
<br> Messages are sent using {@link org.linphone.core.LinphoneChatRoom} object. First step is to create a {@link org.linphone.core.LinphoneCore#createChatRoom chat room }
from a peer sip uri.
<pre>
<code>
	LinphoneChatRoom chat_room = lc.createChatRoom("sip:joe@sip.linphone.org");
</pre>
</code>
<br>Once created, messages are sent using function {@link org.linphone.core.LinphoneChatRoom#sendMessage }  . 
<pre>
<code>
	chat_room.sendMessage("Hello world"); /*sending message*/
</pre>
</code>
<br>Incoming message are received from {@link org.linphone.core.LinphoneCoreListener#textReceived  a listener }
<pre>
<code>
	void textReceived(LinphoneCore lc, LinphoneChatRoom cr,LinphoneAddress from,String message) {
		System.out.println("Message ["+message+"] received from ["+from+"] ");
	}
</code>
</pre>

<h3>
<a name="echo">Sound and echo cancellation settings</a>
</h3>
<b>Sound levels</b>
<br> 
It is possible to tune the microphone input gain and speaker/receiver output gain by setting parameters into the linphonerc factory config file loaded when instanciating the {@link org.linphone.core.LinphoneCore LinphoneCore}. These gains are liblinphone's internal software gains and are unrelated to volume levels managed by the operating system. For example: <br>
<pre>
<code>
[sound]
#set the speaker or receiver playback gain in dbm0 (0 db = no change). 
playback_gain_db=-3
#set the microphone gain in linear scale:
mic_gain=0.1
</code>
</pre>

<br>

<b>Echo cancellation</b>
<br>
On Android devices, there are two kind of situations regarding echo cancellation:<br>
<ul>
	<li>The new (after 2011) high end devices, on which manufacturers often include a hardware echo cancellation. If available, liblinphone will make use of it and no software correction is required. Source file linphone-android/submodules/linphone/mediastreamer2/java/src/org/linphone/mediastream/video/capture/hwconf/Hacks.java contains a method hasBuiltInEchoCanceller() that returns true if an hardware echo canceller is available, based on device model identifier. The current list is incomplete.</li>
	<li>The other devices, for which it is recommended to enable the software echo canceller of liblinphone.</li>
</ul>

<br>
<b>Echo calibration tool</b>
<br>
The echo calibration procedure is a five second audio test which consists in playing small beeps to the receiver while the microphone input is recorded.
If the device is subject to echo (or doesn't have hardware echo cancellation), then beeps recorded by the microphone will be detected and a measurement of echo delay can be computed.
Echo calibration procedure can be started by calling {@link org.linphone.core.LinphoneCore#startEchoCalibration LinphoneCore.startEchoCalibration}.
The measurement of the echo delay is important to save CPU computations by restricting the temporal area where the software echo canceller has to perform.
<br>

<br>
<b>Echo limiter</b>
<br>
The echo limiter is a liblinphone algorithm to clear out echo with a brute force method. It consists in cutting down the microphone signal when active signal is played by the speaker/receiver, to prevent voice to feed back into the microphone. This algorithm has disadvantages compared to the hardware or software echo cancellers because the remote user will be not hear any background noise when speaking, which is confusing. As a result the echo limiter method shall be used only under situation where echo canceller can't perform, that is loud signals with heavy saturations, which usually happens when using the device in speaker mode. Echo limiter can be enabled or disabled during a call with {@link org.linphone.core.LinphoneCall#enableEchoLimiter LinphoneCall.enableEchoLimiter()}.
<br>

<br>
<b>Recommandations to applications for optimal audio performance</b>
<br>

<br>
In order to benefit from the best echo cancellation solution, we recommend applications to run the following procedure, when they are run for the first time:<br>
<ul>
	<li>Use the Hacks.hasBuiltInEchoCanceller() method to first check if the device has hardware echo cancellation. If yes, then echo canceller must be turned off.</li>
	<li>If hasBuiltInEchoCanceller() returned false, then it is recommended to run the echo calibration procedure. This procedure can produce the following results:
		<ul>
			<li>success with no echo detected: it means that the device has an hardware echo canceller but is not (yet) referenced in our list of devices having hardware echo cancellation. Echo cancellation should be disabled with {@link org.linphone.core.LinphoneCore#enableEchoCancellation LinphoneCore.enableEchoCancellation(false)}</li>
			<li>success with an estimated echo delay: the echo canceller should be enabled.</li>
			<li>failure: it means that some echo has been detected but the delay could not be estimated. In this case it is recommended to activate the echo canceller. A typical for android minimum delay of 250 ms will be used as default.</li>
		</ul>
	</li>
</ul>

During calls, the echo limiter should be disabled while using the receiver, but enabled while using the hands-free speaker. It is also recommended to disable echo canceller while using the echo limiter, because the first one would be useless. Therefore you should have the following situations:
<ul>
	<li>While using the receiver</li>
		<ul>
			<li>Echo canceller enabled, unless the device has hardware echo cancellation</li>
			<li>Echo limiter disabled</li>
		</ul>
	<li>While using the hands-free speaker</li>
		<ul>
			<li>Echo canceller disabled</li>
			<li>Echo limiter enabled, unless the device has hardware echo cancellation.</li>
		</ul>
	</li>
</ul>
Controlling echo limiter during a call has to be done with {@link org.linphone.core.LinphoneCall#enableEchoLimiter LinphoneCall.enableEchoLimiter()}.
Controlling echo canceller during a call has to be done with {@link org.linphone.core.LinphoneCall#enableEchoCancellation LinphoneCall.enableEchoCancellation()}.


<br><br>
<b>Echo limiter settings</b>
<br>
Echo limiter requires settings to be defined in linphonerc factory config file for correction operation.
Typical settings are:
<pre>
<code>
[sound]
el_type=mic
#speaker energy threshold (linear scale) above which echo limiter decreases mic gain.
el_thres=0.03
#attenuation applied to mic gain (linear scale)
el_force=100000
#minimum time in milliseconds during which attenuation is applied
el_sustain=600
#double talk detection: threshold of ratio mic-energy/speaker-energy above which mic input is sent anyway.
el_transmit_thres=1.7
#noise gate floorgain (gain applied when no voice is detected).
ng_floorgain=0.01
</code>
</pre>

Up to date settings must be found from linphone-android/res/raw/linphonerc file.

<br>

</body>
</html>